import { effect, track, trigger, ITERATE_KEY } from "./index.js";

// 5.6 只读与浅只读

// 【1】增加第三个参数 isReadonly，代表是否只读，默认为 false，即非只读
function createReactive(target, isShallow = false, isReadonly = false) {
  return new Proxy(target, {
    get(target, key, receiver) {
      if (key === "raw") {
        return target;
      }
      // 非只读的情况下才需要建立响应联系
      if (!isReadonly) {
        track(target, key);
      }
      const res = Reflect.get(target, key, receiver);
      if (isShallow) return res;
      if (typeof res === "object" && res !== null) {
        // 【3】为了实现深只读，这里需要递归的调用readonly函数将数据包装成只读的代理对象
        return isReadonly ? readonly(res) : reactive(res);
      }
      return res;
    },
    set(target, key, val, receiver) {
      if (isReadonly) {
        console.warn(`属性${key}是只读的`);
        return true;
      }
      const oldVal = target[key];
      const type = Object.prototype.hasOwnProperty.call(target, key)
        ? "SET"
        : "ADD";
      const res = Reflect.set(target, key, val, receiver);

      if (target === receiver.raw) {
        // console.log(" receiver 就是 target 的代理对象");
        if (oldVal !== val && (oldVal === oldVal || val === val)) {
          trigger(target, key, type);
        }
      }

      return res;
    },
    deleteProperty(target, key) {
      if (isReadonly) {
        console.warn(`属性${key}是只读的`);
        return true;
      }
      const hadKey = Object.prototype.hasOwnProperty.call(target, key);
      const res = Reflect.deleteProperty(target, key);
      if (res && hadKey) {
        trigger(target, key, "DELETE");
      }
      return res;
    },
    has(target, key) {
      return Reflect.has(target, key);
    },
    ownKeys(target, key) {
      track(target, ITERATE_KEY);
      return Reflect.ownKeys(target);
    },
  });
}
function reactive(target) {
  return createReactive(target);
}

function readonly(target) {
  return createReactive(target, false, true);
}

const obj2 = readonly({
  a: 1,
  foo: {
    bar: 1,
  },
});
// 【4】重新运行下面的逻辑 会发现当修改obj2.foo.bar的时候不会触发effect，而是提示告警信息‘属性bar是只读的’
effect(() => {
  // console.log(obj2.a); // 【2】修改obj2.a的值提示警告信息‘属性a是只读的’
  console.log("effect==", obj2.foo.bar); // 【2】这里不会触发警告信息，下面obj2.foo.bar修改后 这里仍然可以触发
  // 【2】上面实现的 readonly 函数更应该叫作shallowReadonly，因为它没有做到深只读
});
// obj2.a = 2;
obj2.foo.bar = 2;

// 【5】实现一个浅只读
function shallowReadonly(target) {
  return createReactive(target, true, true);
}
const obj3 = shallowReadonly({
  a: 1,
  foo: {
    bar: 1,
  },
});
effect(() => {
  // console.log("effect=obj3=", obj3.a); // 属性a是只读的
  console.log("effect=obj3=", obj3.foo.bar); // 不会建立响应关系，因为浅只读
});
// obj3.a = 2;
obj3.foo.bar = 2;
